package com.filetransfer.controller;
import com.filetransfer.api.ApiHelper;
import com.filetransfer.api.ShareCollection;
import com.filetransfer.api.generated.MessageControllerApi;
import com.filetransfer.api.generated.ShareItemControllerApi;
import com.filetransfer.api.generated.invoker.Configuration;
import com.filetransfer.api.generated.models.ModelFile;
import com.filetransfer.api.generated.models.ShareItem;
import com.filetransfer.api.upload.FileUpload;
import com.filetransfer.api.upload.ProgressInfo;
import com.filetransfer.utils.StringFormat;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@Slf4j
public class FileTransferController {
    public ShareCollection.ShareResultToken chooseFile(JFrame parentFrame, OneFileCallback onFileStart, OneFileCallback onFileComplete, Runnable onFailed, @Nullable FilesChunkProgressListener onProgress) {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setMultiSelectionEnabled(true); // 允许multi选文件
        int result = fileChooser.showOpenDialog(parentFrame);
        if (result == JFileChooser.APPROVE_OPTION) {
            File[] file = fileChooser.getSelectedFiles();
            return startFileTransfer(file, onFileStart, onFileComplete, onFailed, onProgress);
        } else {
            return null;
        }
    }
    public record CurrentFileInfo(File currentFile, int index, int count) {}
    public interface FilesChunkProgressListener {
        void onProgress(CurrentFileInfo current, ProgressInfo progressInfo);
    }
    public interface OneFileCallback {
        void call(File file, int index, int length);
    }
    public ShareCollection.ShareResultToken startFileTransfer(File[] files, OneFileCallback onFileStart, OneFileCallback onFileComplete, Runnable onFailed, @Nullable FilesChunkProgressListener onProgress) {
        try {
            int chunkSize = 10 * 1024 * 1024;
            var shareCollection = new ShareCollection(chunkSize);
            int i = 0;
            for (File file : files) {
                var index = i++;
                onFileStart.call(file, index, files.length);
                shareCollection.addFile(file, progress -> {
                    onProgress.onProgress(new CurrentFileInfo(file, index, files.length), progress);
                });
                onFileComplete.call(file, index, files.length);
            }
            var result = shareCollection.makeShare();
            System.out.println("分享码：" + result.share());
            for (URL link : result.links()) {
                System.out.println("下载链接：" + link.toString());
            }
            return result;
        } catch (Exception e) {
            onFailed.run();
            System.err.println("文件传输失败：" + e.getMessage());
            return null;
        }
    }
    public void inputShareCode(Consumer<String> onCodeReceived) {
        JFrame inputFrame = new JFrame("输入分享码");
        inputFrame.setSize(400, 300);
        inputFrame.setLayout(null);
        inputFrame.setLocationRelativeTo(null);
        JLabel instructionLabel = new JLabel("请输入分享码：", JLabel.CENTER);
        instructionLabel.setBounds(50, 30, 300, 30);
        inputFrame.add(instructionLabel);
        JTextField inputField = new JTextField();
        inputField.setBounds(75, 80, 250, 30);
        inputFrame.add(inputField);
        //自动转换为大写
        inputField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                var upper = inputField.getText().toUpperCase();
                if (!upper.equals(inputField.getText())) inputField.setText(upper);
            }
        });
        JButton confirmButton = new JButton("确认接受");
        confirmButton.setBounds(140, 130, 120, 40);
        confirmButton.addActionListener(e -> {
            String code = inputField.getText().trim();
            if (code.isEmpty()) {
                JOptionPane.showMessageDialog(inputFrame, "请输入有效的分享码！", "错误", JOptionPane.ERROR_MESSAGE);
                return;
            }
            inputFrame.dispose();
            onCodeReceived.accept(code);
        });
        inputFrame.add(confirmButton);
        inputFrame.setVisible(true);
    }
    public void fetchShare(String code, Consumer<ShareItem> onLinkReceived, Runnable onFailed) {
        try {
            var api = new ShareItemControllerApi(ApiHelper.newApiClient());
            ShareItem share = api.getShareItemById(code);
            if (share == null) {
                throw new Exception("分享码无效或文件不存在！");
            }
            onLinkReceived.accept(share);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "操作失败：" + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
            onFailed.run();
        }
    }
    public void previewAndChooseLinksToDownload(ShareItem share, Consumer<List<ModelFile>> onFilesSelected) {
        JFrame previewFrame = new JFrame("选择下载文件");
        previewFrame.setSize(400, 300);
        previewFrame.setLayout(new BorderLayout());
        previewFrame.setLocationRelativeTo(null);
        var messages = share.getMessages();
        String messageToShowOnRight = "暂无留言";
        if (messages != null && !messages.isEmpty()) {
            messageToShowOnRight = "留言：\n" + StringFormat.formatMessage(messages);
        }
        JLabel messageLabel = new JLabel("<html>" + messageToShowOnRight.replace("\n", "<br>") + "</html>", JLabel.LEFT);
        messageLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); // 添加外边距
        previewFrame.add(messageLabel, BorderLayout.NORTH);
        assert share.getFiles() != null;
        DefaultListModel<ModelFile> listModel = new DefaultListModel<>();
        share.getFiles().forEach(listModel::addElement);
        JList<ModelFile> fileList = new JList<>(listModel);
        fileList.setCellRenderer(new FileListCellRenderer());
        fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        JScrollPane scrollPane = new JScrollPane(fileList);
        scrollPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); // 添加外边距
        BorderLayout tipsLayout = new BorderLayout();
        JPanel tips = new JPanel(tipsLayout);
        var color = UIManager.getColor("Component.focusColor");
        JLabel instructionLabel = new JLabel("按住Shift键/Ctrl键可多选", JLabel.CENTER);
        instructionLabel.setForeground(color);
        instructionLabel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); // 添加外边距
        //列表下方加一行灰色的小字，说明：“按住Shift键/Ctrl键可多选” ，以及"Ctrl+A"全选超连接可以点击
        tips.add(instructionLabel, BorderLayout.CENTER);
        tips.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); // 添加外边距
        JLabel selectAllLabel = new JLabel("<html><u>Ctrl+A 全选</u></html>");
        selectAllLabel.setForeground(color);
        selectAllLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        selectAllLabel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                fileList.setSelectionInterval(0, listModel.getSize() - 1);
            }
        });
        tips.add(selectAllLabel, BorderLayout.WEST);
        var selectNoneLabel = new JLabel("<html><u>取消选择</u></html>");
        selectNoneLabel.setForeground(color);
        selectNoneLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        selectNoneLabel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                fileList.clearSelection();
            }
        });
        tips.add(selectNoneLabel, BorderLayout.EAST);
        var centerPanel = new JPanel(new BorderLayout());
        centerPanel.add(scrollPane, BorderLayout.CENTER);
        centerPanel.add(tips, BorderLayout.SOUTH);
        previewFrame.add(centerPanel, BorderLayout.CENTER);
        JButton confirmButton = new JButton("选中文件后点击下载");
        confirmButton.setEnabled(false);
        fileList.addListSelectionListener(e -> {
            var selectedFileCount = fileList.getSelectedIndices().length;
            if (selectedFileCount > 0) {
                confirmButton.setEnabled(true);
                if (selectedFileCount == (long) share.getFiles().size()) {
                    confirmButton.setText("确认下载全部文件");
                } else {
                    confirmButton.setText("确认下载(" + selectedFileCount + "个文件)");
                }
            } else {
                confirmButton.setEnabled(false);
                confirmButton.setText("未选择文件");
            }
        });
        confirmButton.addActionListener(e -> {
            List<ModelFile> selectedFiles = fileList.getSelectedValuesList();
            if (selectedFiles.isEmpty()) {
                JOptionPane.showMessageDialog(previewFrame, "请选择至少一个文件！", "错误", JOptionPane.ERROR_MESSAGE);
                return;
            }
            previewFrame.dispose();
            onFilesSelected.accept(selectedFiles);
        });
        confirmButton.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); // 添加外边距
        previewFrame.add(confirmButton, BorderLayout.SOUTH);
        previewFrame.setVisible(true);
    }
    public static class FileListCellRenderer extends JPanel implements ListCellRenderer<ModelFile> {
        private final JCheckBox checkBox;
        private final JLabel fileNameLabel;
        private final JLabel fileSizeLabel;
        public FileListCellRenderer() {
            setLayout(new BorderLayout());
            checkBox = new JCheckBox();
            fileNameLabel = new JLabel();
            fileSizeLabel = new JLabel();
            add(checkBox, BorderLayout.WEST);
            add(fileNameLabel, BorderLayout.CENTER);
            add(fileSizeLabel, BorderLayout.EAST);
        }
        @Override
        public Component getListCellRendererComponent(JList<? extends ModelFile> list, ModelFile value, int index, boolean isSelected, boolean cellHasFocus) {
            checkBox.setSelected(isSelected);
            checkBox.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (checkBox.isSelected()) {
                        list.addSelectionInterval(index, index);
                    } else {
                        list.removeSelectionInterval(index, index);
                    }
                    log.info("选择文件：" + value.getFileName());
                }
            });
            fileNameLabel.setText(value.getFileName());
            fileSizeLabel.setText(StringFormat.formatSize(value.getFileSize()));
            if (isSelected) {
                setBackground(list.getSelectionBackground());
                setForeground(list.getSelectionForeground());
            } else {
                setBackground(list.getBackground());
                setForeground(list.getForeground());
            }
            return this;
        }
    }
    public interface DownloadProgressListener {
        void onProgress(int progress);
    }
    public void prepareAndDownloadFile(URL fileUrl, String savePath, Runnable onStartDownload, Consumer<File> onDownloadComplete, Consumer<Exception> onFailed, @Nullable DownloadProgressListener onProgress) throws IOException {
        File saveDirectory = new File(savePath);
        if (!saveDirectory.exists()) {
            if (saveDirectory.mkdirs()) {
                System.out.println("目录创建成功：" + savePath);
            } else {
                throw new IOException("无法创建目录：" + savePath);
            }
        }
        String fileName = getFileNameFromUrl(fileUrl);
        if (fileName == null || fileName.isEmpty()) {
            throw new IOException("无法从URL获取文件名：" + fileUrl);
        }
        String tempFileName = "temp_" + fileName;
        File tempFile = new File(savePath, tempFileName);
        File finalFile = new File(savePath, fileName);
        onStartDownload.run();

        SwingWorker<Void, Integer> worker = new SwingWorker<>() {
            @Override
            protected Void doInBackground()  {
                try {
                    startDownload(fileUrl, tempFile, finalFile, onDownloadComplete, onFailed, onProgress);
                } catch (IOException e) {
                    onFailed.accept(e);
                }
                return null;
            }
        };
        worker.execute();
    }
    private void startDownload(URL fileUrl, File tempFile, File finalFile, Consumer<File> onDownloadComplete, Consumer<Exception> onFailed, @Nullable DownloadProgressListener onProgress) throws IOException {
        URLConnection connection = fileUrl.openConnection();
        int fileSize = connection.getContentLength();
        if (fileSize == -1) {
            System.out.println("无法获取文件大小，下载进度可能不准确。");
        }
//        new Thread(() -> {
        try (InputStream inputStream = connection.getInputStream(); FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            long totalBytesRead = 0;
            int lastProgress = 0;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, bytesRead);
                totalBytesRead += bytesRead;
                if (fileSize > 0 && onProgress != null) {
                    int currentProgress = (int) ((totalBytesRead * 100) / fileSize);
                    if (currentProgress > lastProgress) {
                        onProgress.onProgress(currentProgress);
                        lastProgress = currentProgress;
                    }
                }
            }
        } catch (FileNotFoundException e) {
            log.error("文件不存在", e);
            onFailed.accept(new Exception("文件不存在：" + e.getMessage()));
            return;
        } catch (Exception e) {
            log.error("Error", e);
            onFailed.accept(new Exception("下载失败：" + e.getMessage()));
            return;
        }
        if (tempFile.renameTo(finalFile)) {
            onDownloadComplete.accept(finalFile);
            System.out.println("文件下载完成并重命名为：" + finalFile.getAbsolutePath());
        } else {
            onFailed.accept(new Exception("文件已存在：" + finalFile.getName()));
            tempFile.delete();
        }
//        });
    }
    private String getFileNameFromUrl(URL fileUrl) {
        String Url = fileUrl.toString();
        if (Url == null || Url.isEmpty()) {
            return null;
        }
        return Url.substring(Url.lastIndexOf('/') + 1);
    }
}
